programming4us
           
 
 
Programming

Microsoft ASP.NET 3.5 : Web Services for ASP.NET AJAX Applications (part 2) - Consuming AJAX Web Services

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
7/19/2011 4:54:33 PM

Consuming AJAX Web Services

A referenced ASP.NET AJAX Web service is exposed to the JavaScript code as a class with the same name as the server class, including namespace information. As we’ll see in a moment, the proxy class is a singleton and exposes static methods for you to call. No instantiation is required, which saves time and makes the call trigger more quickly. Let’s take a look at the JavaScript proxy class generated from the public interface of an AJAX Web service.

The Proxy Class

To understand the structure of a JavaScript proxy class, we’ll consider what the ASP.NET AJAX runtime generates for the aforementioned timeservice.asmx Web service. In the following example, the full name of the Web service class is Core35.WebServices.TimeService, and therefore it is the name of the JavaScript proxy as well. Here’s the first excerpt from the script injected into the client page for the time Web service:

Type.registerNamespace('Core35.WebServices');
Core35.WebServices.TimeService = function()
{
Core35.WebServices.TimeService.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
Core35.WebServices.TimeService.prototype =
{
GetTime : function(succeededCallback, failedCallback, userContext)
{
return this._invoke(Core35.WebServices.TimeService.get_path(),
'GetTime', false, {}, succeededCallback,
failedCallback, userContext);
},
GetTimeFormat : function(timeFormat, succeededCallback,
failedCallback, userContext)
{
return this._invoke(Core35.WebServices.TimeService.get_path(),
'GetTimeAsFormat', false, {format:timeFormat},
succeededCallback, failedCallback, userContext);

}
}
Core35.WebServices.TimeService.registerClass(
Core35.WebServices.TimeService',
Sys.Net.WebServiceProxy);
Core35.WebServices.TimeService._staticInstance = new Core35.WebServices.TimeService();



As you can see from the prototype, the TimeService class has two methods—GetTime and GetTimeFormat—the same two methods defined as Web methods in the server-side Web service class. Both methods have an extended signature that encompasses additional parameters other than the standard set of input arguments (as defined by the server-side methods). In particular, you see two callbacks to call—one for the success of the call, and one for failure—and an object that represents the context of the call. Internally, each method on the proxy class yields to a private member of the parent class—Sys.Net.WebServiceProxy—that uses XMLHttpRequest to physically send bytes to the server.

The last statement in the preceding code snippet creates a global instance of the proxy class. The methods you invoke from within your JavaScript to execute remote calls are defined around this global instance, as shown here:

Core35.WebServices.TimeService.GetTime = function(
onSuccess,onFailed,userContext)
{
Core35.WebServices.TimeService._staticInstance.GetTime(
onSuccess, onFailed, userContext);
}

Core35.WebServices.TimeService.GetTimeFormat = function(
format, onSuccess, onFailed, userContext)
{
Core35.WebServices.TimeService._staticInstance.GetTimeFormat(
format, onSuccess, onFailed, userContext);
}

The definition of the proxy class is completed with a few public properties, as described in Table 2.

Table 2. Static Properties on a JavaScript Proxy Class
PropertyDescription
pathGets and sets the URL of the underlying Web service
timeoutGets and sets the duration (in seconds) before the method call times out
defaultSucceededCallbackGets and sets the default JavaScript callback function to invoke for a successful call
defaultFailedCallbackGets and sets the default JavaScript callback function, if any, to invoke for a failed or timed-out call
defaultUserContextGets and sets the default JavaScript object, if any, to be passed to success and failure callbacks

If you set a “default succeeded” callback, you don’t have to specify a “succeeded” callback in any successive call as long as the desired callback function is the same. The same holds true for the failed callback and the user context object. The user context object is any JavaScript object, filled with any information that makes sense to you, that gets automatically passed to any callback that handles the success or failure of the call.

Note

The JavaScript code injected for the proxy class uses the path property to define the URL to the Web service. You can change the property programmatically to redirect the proxy to a different URL.


Executing Remote Calls

A Web service call is an operation that the page executes in response to a user action such as a button click. Here’s the typical way of attaching some JavaScript to a client button click:

<input type="button" value="Get Time" onclick="getTime()" />

The button, preferably, is a client button, but it can also be a classic server-side Button object submit button as long as it sets the OnClientClick property to a piece of JavaScript code that returns false to prevent the alternative default submit action:

<asp:Button ID="Button1" runat="server" Text="Button"

OnClientClick="getTime();return false;" />

The getTime function collects any required input data and then calls the desired static method on the proxy class. If you plan to assign default values to callbacks or the user context object, the best place to do it is in the pageLoad function.

<script language="javascript" type="text/javascript">
function pageLoad()
{
Core35.WebServices.TimeService.set_defaultFailedCallback(methodFailed);
}
function getTime()
{
Core35.WebServices.TimeService.GetTimeFormat(
"ddd, dd MMMM yyyy [hh:mm:ss]", methodComplete);
}
function methodComplete(results, context, methodName)
{
$get("Label1").innerHTML = results;
}
function methodFailed(errorInfo, context, methodName)
{
$get("Label1").innerHTML = String.format(
"Execution of method '{0}' failed because of the
following:\r\n'{1}'",
methodName, errorInfo.get_message());
}
</script>


Because the Web service call proceeds asynchronously, you need callbacks to catch up both in the case of success and failure. The signature of the callbacks is similar, but the internal format of the results parameter can change quite a bit:
function method(results, context, methodName)

Table 3 provides more details about the various arguments.

Table 3. Arguments for JavaScript Web Service Callback Functions
ArgumentDescription
resultsIndicates the return value from the method in the case of success. In the case of failure, a JavaScript Error object mimics the exception that occurred on the server during the execution of the method.
contextThe user context object passed to the callback.
methodNameThe name of the Web service method that was invoked.

Based on the previous code, if the call is successful the methodCompleted callback is invoked to update the page. The result is shown in Figure 2.

Figure 2. A remote call made from the client

Error Handling

The “failed” callback kicks in when an exception occurs on the server during the execution of the remote method. In this case, the HTTP response contains an HTTP 500 error code (internal error) and the body of the response looks like the following:

{"message":"Exception thrown for testing purposes",
"stackTrace":" at Core35.WebServices.MyDataService.Throw() in
d:\\Core35\\App_Code\\Services\\MyDataService.cs:line
62","ExceptionType":"System.InvalidOperationException"}

On the client, the server exception is exposed through a JavaScript Error object dynamically built based on the message and a stack trace received from the server. This Error object is exposed to the “failed” callback via the results argument. You can read back the message and stack trace through message and stackTrace properties on the Error object.

You can use a different error handler callback for each remote call, or you can designate a default function to be invoked if one is not otherwise specified. However, ASP.NET AJAX still defines its own default callback, which is invoked when it gets no further information from the client developer. The system-provided error handler callback simply pops up a message box with the message associated with the server exception. If you define your own “failed” callback, you can avoid message boxes and incorporate any error message directly in the body of the page.

Giving User Feedback

A remote call might take a while to complete because the operation to execute is fairly heavy or just because of the network latency. In any case, you might feel the need to show some feedback to the user to let her know that the system is still working. We saw that the Microsoft AJAX library has a built-in support for an intermediate progress screen and also a client-side eventing model. Unfortunately, this functionality is limited to calls that originate within updatable panels. For classic remote method calls, you have to personally take care of any user feedback.

You bring up the wait message, the animated GIF, or whatever else you need just before you call the remote method:

function takeaWhile()
{
// In this example, the Feedback element is a <span> tag
$get("Feedback").innerHTML = "Please, wait ...";
Core35.WebServices.MySampleService.VeryLengthyTask(
methodCompletedWithFeedback, methodFailedWithFeedback);
}

In the “completed” callback, you reset the user interface first and then proceed:

function methodCompletedWithFeedback(results, context, methodName)
{
$get("Feedback").innerHTML = "";
...
}

Note that you should also clear the user interface in the case of errors. In addition to showing some sort of wait message to the user, you should also consider that other elements in the page might need to be disabled during the call. If this is the case, you need to disable them before the call and restore them later.

Handling Timeouts

A remote call that takes a while to complete is not necessarily a good thing for the application. Keep in mind that calls that work asynchronously for the client are not necessarily asynchronous for the ASP.NET runtime. In particular, note that when you make a client call to an .asmx Web service, you are invoking the .asmx directly. For this request, only a synchronous handler is available in the ASP.NET runtime. This means that regardless of how the client perceives the ongoing call, an ASP.NET thread is entirely blocked (waiting for results) until the method is done. To mitigate the impact of lengthy AJAX methods on the application scalability, you can set a timeout:

Core35.WebServices.MySampleService.set_timeout(3000);

The timeout attribute is global and applies to all methods of the proxy class. This means that if you want to time out only one method call, you have to reset the timeout for all calls you’re making from the page. To reset the timeout, you just set the timeout property to zero:

Core35.WebServices.MySampleService.set_timeout(0);

When the request times out, there’s no response received from the server. It’s simply a call that is aborted from the client. After all, you can’t control what’s going on with the server. The best you can do is abort the request on the client and take other appropriate measures, such as having the user try again later.

Considerations for AJAX-Enabled Web Services

Now that we know how to tackle AJAX-enabled Web services, it would be nice to spend some time reflecting on some other aspects of them—for example, why use local services?

Why Local Web Services?

To make sure you handle AJAX Web services the right way, think of them as just one possible way of exposing a server API to a JavaScript client. You focus on the interface that must be exposed and then choose between ASP.NET Web services, WCF services, and page methods for its actual implementation. Looking at it from this angle, you might find it to be quite natural that the Web service has to be hosted in the same ASP.NET AJAX application that is calling it.

But why can’t you just call into any SOAP-based Web services out there? There are two main reasons: security and required support for JSON serialization.

For security reasons, browsers tend to stop script-led cross-site calls. (Not all scripts are benevolent.) Most browsers bind scripted requests to what is often referred to as the “same origin policy.” Defined, it claims that no documents can be requested via script that have a different port, server, or protocol than the current page. In light of this, you can use the XMLHttpRequest object to place asynchronous calls as long as your request hits the same server endpoint that served the current page.

Because of the cross-site limitations of XMLHttpRequest in most browsers, ASP.NET doesn’t allow you to directly invoke a Web service that lives on another IIS server or site. Without this limitation, nothing would prevent you from invoking a Web service that is resident on any platform and Web server environment, but then your users are subject to potential security threats from less scrupulous applications. With this limitation in place, though, an additional issue shows up: the inability of your host ASP.NET AJAX environment to build a JavaScript proxy class for the remote, non–ASP.NET AJAX Web service.

Note

Because of the impact that blocked cross-site calls have on general AJAX development, a new standard might emerge in the near future to enable such calls from the browser. It might be desirable that the client sends the request and dictates the invoked server accept or deny cross-site calls made via XMLHttpRequest. As of this writing, though, the possibility of direct cross-site calls from AJAX clients (not just ASP.NET AJAX Extensions) remains limited to the use of IFRAMEs and finds no built-in support in ASP.NET 3.5.


Why JSON-Based Web Services?

A call to a Web service hosted by the local ASP.NET AJAX application is not conducted using SOAP as you might expect. SOAP is XML-based, and parsing XML on the client is very expensive in terms of memory and processing resources. It means that an XML parser must be available in JavaScript, and an XML parser is never an easy toy to build and manage, especially using a relatively lightweight tool such as JavaScript. So a different format is required to pack messages to be sent and unpack messages just received. Like SOAP and XML schemas together, though, this new format must be able to serialize an object’s public properties and fields to a serial text-based format for transport. The format employed by ASP.NET AJAX Web services is JSON.

The client-side ASP.NET AJAX network stack takes care of creating JSON strings for each parameter to pass remotely. The JavaScript class that does that is called Sys.Serialization.JavaScriptSerializer. On the server, ad hoc formatter classes receive the data and use .NET reflection to populate matching managed classes. On the way back, .NET managed objects are serialized to JSON strings and sent over. The script manager is called to guarantee that proper classes referenced in the JSON strings—the Web service proxy class—exist on the client.

Runtime Support for JSON-Based Web Services

As a developer, you don’t necessarily need to know much about the JSON format. You normally don’t get close enough to the heart of the system to directly manage JSON strings. However, a JSON string represents an object according to the following sample schema:

{
"__type":"IntroAjax.Customer",
"ID":"ANATR",
"ContactName":"Ana Trujillo"
...
}

You’ll find a number of comma-separated tokens wrapped in curly brackets. Each token is, in turn, a colon-separated string. The left part, in quotes, represents the name of the property; the right part, in quotes, represents the serialized version of the property value. If the property value is not a primitive type, it gets recursively serialized via JSON. If the object is an instance of a known type (that is, it is not an untyped JavaScript associative array), the class name is inserted as the first piece of information associated with the __type property. Any information being exchanged between an ASP.NET AJAX client and an ASP.NET AJAX Web service is serialized to the JSON format.

To the actual Web service, the transport format is totally transparent—be it SOAP, JSON, plain-old XML (POX), or whatever else. The runtime infrastructure takes care of deserializing the content of the message and transforms it into valid input for the service method. The ASP.NET AJAX runtime recognizes a call directed to an AJAX Web service because of the particular value of the Content-Type request header. Here’s an excerpt from the Microsoft AJAX client library where the header is set:

request.get_headers()['Content-Type'] = 'application/json; charset=utf-8';

The value of this header is used to filter incoming requests and direct them to the standard ASP.NET XML Web service HTTP handler or to the made-to-measure ASP.NET AJAX Web service handler that will do all the work with the JSON string.

Other -----------------
- Microsoft ASP.NET 3.5 : AJAX-Enabled Web Services - Implementing the AJAX Paradigm
- The Art of SEO : Measuring Search Traffic (part 2)
- The Art of SEO : Measuring Search Traffic (part 1)
- Programming Excel with VBA and .NET : Tasks in Visual Basic - Do Math
- Programming Excel with VBA and .NET : Tasks in Visual Basic - Interact with Users
- Context and Interception : The .NET Context
- Context and Interception : .NET Component Services
- Optimizing for Vertical Search : Mobile, Video & Multimedia Search
- Programming WCF Services : Data Contracts - Collections (part 2) - The CollectionDataContract Attribute & Dictionaries
- Programming WCF Services : Data Contracts - Collections (part 1) - Concrete Collections & Custom Collections
- iPhone Programming : The Image Picker View Controller - Adding the Image Picker to the City Guide Application
- iPhone Programming : Other View Controllers - Modal View Controllers
- jQuery 1.3 : DOM Manipulation - Inserting new elements
- jQuery 1.3 : DOM Manipulation - Manipulating attributes
- DirectX 10 Game Programming : Adding the DirectX Libraries
- jQuery 1.3 : AJAX - Additional options
- jQuery 1.3 : AJAX and events & Security limitations
- jQuery 1.3 : AJAX - Keeping an eye on the request
- jQuery 1.3 : AJAX - Passing data to the server
- iPhone Programming : Other View Controllers - Tab Bar Applications
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us